package com.tech.platform.cms.databases.mybatis.sqlParser.tenantParser;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSchemaSqlParser;
import com.tech.platform.cms.databases.mybatis.sqlParser.tenantParser.handler.TenantTableHandler;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.statement.update.Update;

import java.util.List;

/**
 * @author shengqiang.wu
 * @date 2019/12/25/025 10:25
 * @desc
 */
public class TenantTableSqlParser extends TenantSchemaSqlParser{

    @Override
    public void processInsert(Insert insert) {
        TenantTableHandler tenantTableHandler = (TenantTableHandler)this.getTenantSchemaHandler();
        Table oriTable = insert.getTable();
        tenantTableHandler.generatorNewTable(oriTable);

        //insert into table (select * from table2)
        if(insert.getSelect()!=null){
            this.processSelectBody(insert.getSelect().getSelectBody());
        }
    }

    @Override
    public void processDelete(Delete delete) {
        TenantTableHandler tenantTableHandler = (TenantTableHandler)this.getTenantSchemaHandler();
        Table oriTable = delete.getTable();
        tenantTableHandler.generatorNewTable(oriTable);

        //delete join
        List<Join> joins = delete.getJoins();
        if(CollUtil.isNotEmpty(joins)){
            joins.forEach(j -> {
                processJoin(j);
                processFromItem(j.getRightItem());
            });
        }
    }

    @Override
    public void processUpdate(Update update) {
        TenantTableHandler tenantTableHandler = (TenantTableHandler)this.getTenantSchemaHandler();
        List<Table> tableList = update.getTables();
        Assert.isTrue(null != tableList && tableList.size() < 2,
                "Failed to process multiple-table update, please exclude the statementId");
        Table table = tableList.get(0);
        tenantTableHandler.generatorNewTable(table);

        if(update.getSelect()!=null){
            processSelectBody(update.getSelect().getSelectBody());
        }

        if(update.getFromItem()!=null){
            processFromItem(update.getFromItem());
        }

        //TODO update 中的joins不知是怎样的形式存在SQL中的,有或者已经被FromItem包含解析了,需要在后续的代码中调试
    }

    @Override
    public void processSelectBody(SelectBody selectBody) {
        if(selectBody!=null){
            if(selectBody instanceof PlainSelect){
                processPlainSelect((PlainSelect)selectBody);
            }
        }else if (selectBody instanceof WithItem) {
            WithItem withItem = (WithItem) selectBody;
            if (withItem.getSelectBody() != null) {
                processSelectBody(withItem.getSelectBody());
            }
        } else {
            SetOperationList operationList = (SetOperationList) selectBody;
            if (operationList.getSelects() != null && operationList.getSelects().size() > 0) {
                operationList.getSelects().forEach(this::processSelectBody);
            }
        }
    }

    protected void processPlainSelect(PlainSelect plainSelect){
        TenantTableHandler tenantTableHandler = (TenantTableHandler)this.getTenantSchemaHandler();
        FromItem fromItem = plainSelect.getFromItem();
        //单表查询
        if(fromItem instanceof Table){
            tenantTableHandler.generatorNewTable((Table) fromItem);
        }else {
            processFromItem(fromItem);
        }

        List<Join> joins = plainSelect.getJoins();
        if (joins != null && joins.size() > 0) {
            joins.forEach(j -> {
                processJoin(j);
                processFromItem(j.getRightItem());
            });
        }
    }

    protected void processFromItem(FromItem fromItem) {
        //select * from a where id in (select id form b)
        if(fromItem instanceof SubSelect){
            processSelectBody(((SubSelect)fromItem).getSelectBody());
        }

        if(fromItem instanceof SubJoin){
            List<Join> joins = ((SubJoin) fromItem).getJoinList();
            if(CollUtil.isNotEmpty(joins)){
                for (Join join : joins){
                    processJoin(join);
                }
            }

            if (((SubJoin) fromItem).getLeft() != null) {
                processFromItem(((SubJoin) fromItem).getLeft());
            }
        }
        else if (fromItem instanceof LateralSubSelect) {
            LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem;
            if (lateralSubSelect.getSubSelect() != null) {
                SubSelect subSelect = lateralSubSelect.getSubSelect();
                if (subSelect.getSelectBody() != null) {
                    processSelectBody(subSelect.getSelectBody());
                }
            }
        }
    }

    protected void processJoin(Join join) {
        TenantTableHandler tenantTableHandler = (TenantTableHandler)this.getTenantSchemaHandler();
        if (join.getRightItem() instanceof Table) {
            Table fromTable = (Table) join.getRightItem();
            tenantTableHandler.generatorNewTable(fromTable);
        }
    }
}
